#pragma once
#include <iostream>
#include <string>
#include <functional>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>

#include "Reactor.hpp"

class Reactor;
class Connection;

using func_t = std::function<void(Connection *)>;

class Connection
{
    static const int defaultport = 8888;

public:
    Connection(int sockfd, uint32_t events, Reactor *R) : _fd(sockfd), _events(events), _R(R), _clientport(defaultport) {}
    int GetSockFd()
    {
        return _fd;
    }

    Reactor *GetReactor()
    {
        return _R;
    }

    std::string &GetInBuffer()
    {
        return _inbuffer;
    }

    std::string &GetOutBuffer()
    {
        return _outbuffer;
    }

    std::string &GetExepBuffer()
    {
        return _exepbuffer;
    }

    void SetClientAddr(const struct sockaddr_in &addr)
    {
        _clientip = inet_ntoa(addr.sin_addr);
        _clientport = ntohs(addr.sin_port);
    }

    void SetEvents(uint32_t events)
    {
        _events = events;
    }

    void Register(func_t reader, func_t writer, func_t exepter)
    {
        _reader = reader;
        _writer = writer;
        _exepter = exepter;
    }

    void Read()
    {
        _reader(this);
    }
    void PushReadBuffer(const std::string &buffer)
    {
        _inbuffer += buffer;
    }

    void PushOutBuffer(const std::string &buffer)
    {
        _outbuffer += buffer;
    }

    void Write()
    {
        _writer(this);
    }

    bool OutEmpty()
    {
        return _outbuffer.empty();
    }

    void Excepte()
    {
        _exepter(this);
    }

    void Close()
    {
        close(_fd);
    }

    ~Connection() {}

private:
    int _fd;
    uint32_t _events;

    std::string _inbuffer;
    std::string _outbuffer;
    std::string _exepbuffer;

    Reactor *_R;

    std::string _clientip;
    uint16_t _clientport;

    func_t _reader;
    func_t _writer;
    func_t _exepter;
};